; void monocromatizar_uno_asm (	unsigned char *src,	unsigned char *dst,	int h, int w, int src_row_size,	int dst_row_size );
										;	RDI,				RSI,	RDX, 	RCX, 		R8,				 R9

global monocromatizar_uno_asm

section .text

%define destino_row_size qword [rbp - 8]
%define fuente_row_size qword [rbp - 16]
%define src_rest qword [rbp - 24]
%define dst_rest qword [rbp - 32]

%define mascara dword 0xFFFFFFFF
%define NULL qword 0

monocromatizar_uno_asm:
	push rbp
	mov rbp, rsp
	sub rsp,32								; para las variables locales
	push rbx
	push r11
	push r12
	push r13
	push r14
	push r15

	
	xor r12,r12
	xor r13,r13
	xor r14,r14
	xor r15,r15
	
	mov r12,rdi									; r12 --> matris fuente
	mov r13,rsi									; r13 --> matris destino
	mov r14d,edx								; r14 --> h --> alto
	mov r15d,ecx								; r15 --> w --> ancho
	

	
	xor rdx,rdx
	mov rdx,r9									; r9 --> dst_row_size	 
	sub rdx, r15					
	mov destino_row_size, rdx					; en destino_row_size guardamos el ancho del padding destino
	
	xor rax,rax
	xor rbx,rbx
	xor rdx,rdx
	
	mov rax,r15
	mov rbx,3
	mul rbx
	mov rbx,r8									; r8 --> src_row_size
	sub rbx, rax
	mov fuente_row_size, rbx					; en fuente_row_size guardamos el ancho del padding fuente
	
	xor rax,rax
	xor rdx,rdx
	mov rax,r15
	mov rbx,4
	div rbx
	mov rax,rdx									; rax --> resto de la divicion
	mov dst_rest,rax							; dst_rest --> cantidad de bytes que restan recorrer en la matris de destino
		
	xor rdx,rdx
	xor rbx,rbx
	mov rax,r15
	mov rbx,3
	mul rbx
	mov rbx,12
	div rbx
	mov rax,rdx									; rax --> resto de la divicion
	mov src_rest,rax							; src_rest --> cantidad de bytes que restan recorrer en la matris de fuente
		
	mov rcx,r15 								; rcx --> contador de columnas
	shr rcx,2									; muevo de a 4 elementos
	xor rbx,rbx									; rbx --> contador de filas
	
ciclo_filas:	
		ciclo_columnas:
			pxor xmm0,xmm0
			pxor xmm1,xmm1
			pxor xmm2,xmm2
			pxor xmm3,xmm3
			pxor xmm4,xmm4
			pxor xmm5,xmm5
			pxor xmm6,xmm6
			pxor xmm7,xmm7	
		
			movdqu xmm1, [r12]					; xmm0 = 16 bytes de informacion
			movdqu xmm2, [r12]					; xmm0 = 16 bytes de informacion		
			punpcklbw xmm1, xmm0
			punpckhbw xmm2, xmm0
			movdqu xmm3, xmm1
			movdqu xmm4, xmm1
			movdqu xmm5, xmm2
			punpcklwd xmm3, xmm0				; xmm3 = | 00 | 01 | 02 | 03 | =  R  G  B  R
			punpckhwd xmm4, xmm0				; xmm4 = | 04 | 05 | 06 | 07 | =  G  B  R  G
			punpcklwd xmm5, xmm0				; xmm5 = | 08 | 09 | 0A | 0B | =  B  R  G  B
			
			;SET xmm0 = | blu08 | blu05 | blu02 | blu0B |
			pxor xmm0,xmm0
			pxor xmm1,xmm1
			pxor xmm2,xmm2
			mov edx, mascara	
			movd xmm0, edx						; xmm0 = | FFFF | 0000 | 0000 | 0000 |
			pslldq xmm0,4						; xmm0 = | 0000 | FFFF | 0000 | 0000 |
			movdqa xmm1,xmm0					; xmm1 = xmm0
			pand xmm1, xmm4						; xmm1 = | 0000 | blu5 | 0000 | 0000 |
			pslldq xmm0,4						; xmm0 = | 0000 | 0000 | FFFF | 0000 |
			movdqa xmm2,xmm0					; xmm2 = xmm0
			pand xmm2, xmm3						; xmm2 = | 0000 | 0000 | blu2 | 0000 |
			pslldq xmm0,4						; xmm0 = | 0000 | 0000 | 0000 | FFFF |
			movd xmm6, edx						; xmm6 = | FFFF | 0000 | 0000 | 0000 |
			paddd xmm6,xmm0						; xmm6 = | FFFF | 0000 | 0000 | FFFF |
			pand xmm6, xmm5						; xmm1 = | blu8 | 0000 | 0000 | bluB |
			paddd xmm1, xmm2					; xmm1 = | 0000 | blu5 | blu2 | 0000 |
			paddd xmm1, xmm6					; xmm1 = | blu8 | blu5 | blu2 | bluB |
			pshufd xmm1, xmm1, 11000110b		; xmm1 = | blu2 | blu5 | blu8 | bluB |

			;SET xmm0 = | gre04 | gre01 | gre0A | gre07 |
			pxor xmm0,xmm0
			pxor xmm2,xmm2
			pxor xmm6,xmm6
			mov edx, mascara
			movd xmm0, edx						; xmm0 = | FFFF | 0000 | 0000 | 0000 |
			pslldq xmm0,4						; xmm0 = | 0000 | FFFF | 0000 | 0000 |
			movdqa xmm2,xmm0					; xmm2 = xmm0
			pand xmm2, xmm3						; xmm2 = | 0000 | gre1 | 0000 | 0000 |
			pslldq xmm0,4						; xmm0 = | 0000 | 0000 | FFFF | 0000 |
			movdqa xmm6,xmm0					; xmm6 = xmm0
			pand xmm6, xmm5						; xmm6 = | 0000 | 0000 | greA | 0000 |
			pslldq xmm0,4						; xmm0 = | 0000 | 0000 | 0000 | FFFF |
			movd xmm7, edx						; xmm7 = | FFFF | 0000 | 0000 | 0000 |
			paddd xmm7,xmm0						; xmm7 = | FFFF | 0000 | 0000 | FFFF |
			pand xmm7, xmm4						; xmm7 = | gre4 | 0000 | 0000 | gre7 |
			paddd xmm2, xmm6					; xmm2 = | 0000 | gre1 | greA | 0000 |
			paddd xmm2, xmm7					; xmm2 = | gre4 | gre1 | greA | gre7 |
			pshufd xmm2, xmm2, 10110001b		; xmm2 = | gre1 | gre4 | gre7 | greA |

			;SET xmm0 = | red00 | red09 | red06 | red03 |
			pxor xmm0,xmm0
			pxor xmm6,xmm6
			pxor xmm7,xmm7
			mov edx, mascara
			movd xmm0, edx						; xmm0 = | FFFF | 0000 | 0000 | 0000 |
			pslldq xmm0,4						; xmm0 = | 0000 | FFFF | 0000 | 0000 |
			movdqa xmm6,xmm0					; xmm6 = xmm0
			pand xmm6, xmm5						; xmm6 = | 0000 | red9 | 0000 | 0000 |
			pslldq xmm0,4						; xmm0 = | 0000 | 0000 | FFFF | 0000 |
			movdqa xmm7,xmm0					; xmm7 = xmm0
			pand xmm7, xmm4						; xmm7 = | 0000 | 0000 | red6 | 0000 |
			pslldq xmm0,4						; xmm0 = | 0000 | 0000 | 0000 | FFFF |
			paddd xmm6, xmm7					; xmm6 = | 0000 | red9 | red6 | 0000 |
			movd xmm7, edx						; xmm7 = | FFFF | 0000 | 0000 | 0000 |
			paddd xmm7,xmm0						; xmm7 = | FFFF | 0000 | 0000 | FFFF |
			pand xmm7, xmm3						; xmm7 = | red0 | 0000 | 0000 | red3 |
			paddd xmm6, xmm7					; xmm6 = | red0 | red9 | red6 | red3 |
			pshufd xmm6, xmm6, 01101100b		; xmm6 = | red0 | red3 | red6 | red9 |
	
			;xmm1 = | blu2 | blu5 | blu8 | bluB |
			;xmm2 = | gre1 | gre4 | gre7 | greA |
			;xmm6 = | red0 | red3 | red6 | red9 |

			paddd xmm2,xmm2 					; xmm2 =  | 2*gre1 | 2*gre4 | 2*gre7 | 2*greA |
			paddd xmm2,xmm1 					; xmm2 =  | 2*gre1+blu2 | 2*gre4+blu5 | 2*gre7+blu8 | 2*greA+bluB |
			paddd xmm2,xmm6 					; xmm2 =  | 2*gre1+blu2+red0 | 2*gre4+blu5+red3 | 2*gre7+blu8+red6 | 2*greA+bluB+red9 |
		
			psrad xmm2,2						; divido xmm2 por 4
			
			packssdw xmm2, xmm2	
			packuswb xmm2, xmm2					; xmm2 = entero sin signo	
	
			movd [r13], xmm2
	
			lea r12, [ r12 + (4*3) ]			; incremento r12 para avanzar a los siguientes 12 elementos de la fila 
			lea r13, [ r13 + (4*1) ]			; incremento r13 para avanzar a los siguientes 4 elementos de la fila
			
			dec rcx
			cmp rcx,NULL
			jne ciclo_columnas		
						
			mov rax,src_rest
			lea r12, [ r12 + rax - (4*3) ]		; acomodo r12 para los ultimos bytes en caso de que la matriz no sea multiplo de 16
			mov rax,dst_rest
			lea r13, [ r13 + rax - (4*1) ]		; acomodo r13 para los ultimos bytes en caso de que la matriz no sea multiplo de 16
			
ultima_vuelta:	
			pxor xmm0,xmm0
			pxor xmm1,xmm1
			pxor xmm2,xmm2
			pxor xmm3,xmm3
			pxor xmm4,xmm4
			pxor xmm5,xmm5
			pxor xmm6,xmm6
			pxor xmm7,xmm7	
		
			movdqu xmm1, [r12]					; xmm0 = 16 bytes de informacion
			movdqu xmm2, [r12]					; xmm0 = 16 bytes de informacion		
			punpcklbw xmm1, xmm0
			punpckhbw xmm2, xmm0
			movdqu xmm3, xmm1
			movdqu xmm4, xmm1
			movdqu xmm5, xmm2
			punpcklwd xmm3, xmm0				; xmm3 = | 00 | 01 | 02 | 03 | =  R  G  B  R
			punpckhwd xmm4, xmm0				; xmm4 = | 04 | 05 | 06 | 07 | =  G  B  R  G
			punpcklwd xmm5, xmm0				; xmm5 = | 08 | 09 | 0A | 0B | =  B  R  G  B
			
			;SET xmm0 = | blu08 | blu05 | blu02 | blu0B |
			pxor xmm0,xmm0
			pxor xmm1,xmm1
			pxor xmm2,xmm2
			mov edx, mascara	
			movd xmm0, edx						; xmm0 = | FFFF | 0000 | 0000 | 0000 |
			pslldq xmm0,4						; xmm0 = | 0000 | FFFF | 0000 | 0000 |
			movdqa xmm1,xmm0					; xmm1 = xmm0
			pand xmm1, xmm4						; xmm1 = | 0000 | blu5 | 0000 | 0000 |
			pslldq xmm0,4						; xmm0 = | 0000 | 0000 | FFFF | 0000 |
			movdqa xmm2,xmm0					; xmm2 = xmm0
			pand xmm2, xmm3						; xmm2 = | 0000 | 0000 | blu2 | 0000 |
			pslldq xmm0,4						; xmm0 = | 0000 | 0000 | 0000 | FFFF |
			movd xmm6, edx						; xmm6 = | FFFF | 0000 | 0000 | 0000 |
			paddd xmm6,xmm0						; xmm6 = | FFFF | 0000 | 0000 | FFFF |
			pand xmm6, xmm5						; xmm1 = | blu8 | 0000 | 0000 | bluB |
			paddd xmm1, xmm2					; xmm1 = | 0000 | blu5 | blu2 | 0000 |
			paddd xmm1, xmm6					; xmm1 = | blu8 | blu5 | blu2 | bluB |
			pshufd xmm1, xmm1, 11000110b		; xmm1 = | blu2 | blu5 | blu8 | bluB |

			;SET xmm0 = | gre04 | gre01 | gre0A | gre07 |
			pxor xmm0,xmm0
			pxor xmm2,xmm2
			pxor xmm6,xmm6
			mov edx, mascara
			movd xmm0, edx						; xmm0 = | FFFF | 0000 | 0000 | 0000 |
			pslldq xmm0,4						; xmm0 = | 0000 | FFFF | 0000 | 0000 |
			movdqa xmm2,xmm0					; xmm2 = xmm0
			pand xmm2, xmm3						; xmm2 = | 0000 | gre1 | 0000 | 0000 |
			pslldq xmm0,4						; xmm0 = | 0000 | 0000 | FFFF | 0000 |
			movdqa xmm6,xmm0					; xmm6 = xmm0
			pand xmm6, xmm5						; xmm6 = | 0000 | 0000 | greA | 0000 |
			pslldq xmm0,4						; xmm0 = | 0000 | 0000 | 0000 | FFFF |
			movd xmm7, edx						; xmm7 = | FFFF | 0000 | 0000 | 0000 |
			paddd xmm7,xmm0						; xmm7 = | FFFF | 0000 | 0000 | FFFF |
			pand xmm7, xmm4						; xmm7 = | gre4 | 0000 | 0000 | gre7 |
			paddd xmm2, xmm6					; xmm2 = | 0000 | gre1 | greA | 0000 |
			paddd xmm2, xmm7					; xmm2 = | gre4 | gre1 | greA | gre7 |
			pshufd xmm2, xmm2, 10110001b		; xmm2 = | gre1 | gre4 | gre7 | greA |

			;SET xmm0 = | red00 | red09 | red06 | red03 |
			pxor xmm0,xmm0
			pxor xmm6,xmm6
			pxor xmm7,xmm7
			mov edx, mascara
			movd xmm0, edx						; xmm0 = | FFFF | 0000 | 0000 | 0000 |
			pslldq xmm0,4						; xmm0 = | 0000 | FFFF | 0000 | 0000 |
			movdqa xmm6,xmm0					; xmm6 = xmm0
			pand xmm6, xmm5						; xmm6 = | 0000 | red9 | 0000 | 0000 |
			pslldq xmm0,4						; xmm0 = | 0000 | 0000 | FFFF | 0000 |
			movdqa xmm7,xmm0					; xmm7 = xmm0
			pand xmm7, xmm4						; xmm7 = | 0000 | 0000 | red6 | 0000 |
			pslldq xmm0,4						; xmm0 = | 0000 | 0000 | 0000 | FFFF |
			paddd xmm6, xmm7					; xmm6 = | 0000 | red9 | red6 | 0000 |
			movd xmm7, edx						; xmm7 = | FFFF | 0000 | 0000 | 0000 |
			paddd xmm7,xmm0						; xmm7 = | FFFF | 0000 | 0000 | FFFF |
			pand xmm7, xmm3						; xmm7 = | red0 | 0000 | 0000 | red3 |
			paddd xmm6, xmm7					; xmm6 = | red0 | red9 | red6 | red3 |
			pshufd xmm6, xmm6, 01101100b		; xmm6 = | red0 | red3 | red6 | red9 |
			
			;xmm1 = | blu2 | blu5 | blu8 | bluB |
			;xmm2 = | gre1 | gre4 | gre7 | greA |
			;xmm6 = | red0 | red3 | red6 | red9 |

			paddd xmm2,xmm2 					; xmm2 =  | 2*gre1 | 2*gre4 | 2*gre7 | 2*greA |
			paddd xmm2,xmm1 					; xmm2 =  | 2*gre1+blu2 | 2*gre4+blu5 | 2*gre7+blu8 | 2*greA+bluB |
			paddd xmm2,xmm6 					; xmm2 =  | 2*gre1+blu2+red0 | 2*gre4+blu5+red3 | 2*gre7+blu8+red6 | 2*greA+bluB+red9 |
			
			psrad xmm2,2						; divido xmm2 por 4
					
			packssdw xmm2, xmm2	
			packuswb xmm2, xmm2					; xmm2 = entero sin signo	
	
			movd [r13], xmm2
		
			lea r12, [ r12 + (4*3) ]			; incremento r12 para avanzar a los siguientes 12 elementos de la fila 
			lea r13, [ r13 + (4*1) ]			; incremento r13 para avanzar a los siguientes 4 elementos de la fila
	
		mov rdx,fuente_row_size
		lea r12, [r12 + rdx]					; seteo a r12 en la nueva fila de src
		mov rdx,destino_row_size
		lea r13, [r13 + rdx]					; seteo a r13 en la nueva fila de dst
		
		mov rcx,r15								; reseteo el contador de columnas
		shr rcx,2								; muevo de a 4 elementos

		inc rbx
		cmp rbx, r14
		jne ciclo_filas
	
fin:
	pop r15
	pop r14
	pop r13
	pop r12
	pop r11
	pop rbx
	add rsp,32
	pop rbp
	ret
